using System;
using System.Collections;
using System.Diagnostics;
using Framework.Interop;

namespace Framework
{
	internal class EnumIDListImpl : IEnumIDList
	{
		private bool _done;
		private readonly EnumOptions _options;
		private readonly IEnumerator _enumerator;

		internal EnumIDListImpl(EnumOptions options, IEnumerable ie)
		{
			this._enumerator = ie == null ? new ArrayList(0).GetEnumerator() : ie.GetEnumerator();
			this._options = options;
			this._done = !MoveNext();
		}

		unsafe int IEnumIDList.Next(uint celt, IntPtr[] rgelt, IntPtr pceltFetched)
		{
			Debug.Assert(celt > 0);

			int i = 0;

			/* try
			{ */

			using (Malloc m = Shell32.GetMalloc())
			{
				if (!this._done)
				{
					do
					{
						rgelt[i++] = ItemIDList.Create(m, ((IFolderObject)_enumerator.Current).Persist()).Ptr;
						celt--;
					} while (celt > 0 & !(this._done = !MoveNext()));
				}

				if (pceltFetched != IntPtr.Zero)
				{
					var fetched = (int*)pceltFetched;
					*fetched = i;
				}

				return this._done && i == 0 ? 1 : 0;
			}

			/* }
			catch (Exception e)
			{
				NameValueCollection info = new NameValueCollection();
				info.Add("done", done.ToString());
				info.Add("opts", Enum.Format(typeof(EnumOptions), opts, "g"));
				ExceptionManager.Publish(e, info);
				throw;
			} */
		}

		void IEnumIDList.Skip(uint celt)
		{
			throw new NotSupportedException();
		}

		void IEnumIDList.Reset()
		{
			throw new NotSupportedException();
		}

		void IEnumIDList.Clone(out IEnumIDList ppenum)
		{
			throw new NotSupportedException();
		}

		private bool Matches(IFolderObject folderObj)
		{
			FolderAttributes attrs = folderObj.Attributes;

			bool hidden = (attrs & FolderAttributes.Hidden) != FolderAttributes.None;
			bool includeHidden = (_options & EnumOptions.IncludeHidden) == EnumOptions.IncludeHidden;

			bool folder = (attrs & FolderAttributes.Folder) != FolderAttributes.None;
			bool includeFolders = (_options & EnumOptions.Folders) == EnumOptions.Folders;
			bool includeNonFolders = (_options & EnumOptions.NonFolders) == EnumOptions.NonFolders;

			bool storage = (attrs & (FolderAttributes.StorageAncestor | FolderAttributes.StorageAncestor)) !=
						   FolderAttributes.None;
			bool includeStorage = (_options & EnumOptions.Storage) == EnumOptions.Storage;

			bool share = (attrs & FolderAttributes.Share) != FolderAttributes.None;
			bool includeShares = (_options & EnumOptions.Shareable) == EnumOptions.Shareable;

			return
				(hidden ? includeHidden : true) &&
				(folder ? includeFolders : includeNonFolders) &&
				(storage ? includeStorage : true) &&
				(share ? includeShares : true);
		}

		private bool MoveNext()
		{
			var hasNext = this._enumerator.MoveNext();
			while (hasNext)
			{
				if (Matches(_enumerator.Current as IFolderObject))
				{
					break;
				}
				hasNext = this._enumerator.MoveNext();
			}

			return hasNext;
		}
	} ;
}
